package com.example.parametervalidator.validator.core.util;

import com.example.parametervalidator.entity.AnnotationInterceptorRegistration;
import com.example.parametervalidator.validator.core.processor.AbstractAnnotationProcessor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@Component
public class SpringContextUtils implements ApplicationContextAware {


    private static ApplicationContext applicationContext;


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextUtils.applicationContext = applicationContext;
    }

    /**
     * 获取ApplicationContext
     * @return
     */
    public static ApplicationContext getApplicationContext(){
        return SpringContextUtils.applicationContext;
    }

    /**
     * 根据class创建空bean
     *
     * @param clazz
     */
    public static void createBean(Class<?> clazz) {

        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
        // 获取bean工厂并转换为DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();

        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
        defaultListableBeanFactory.registerBeanDefinition(clazz.getTypeName(), beanDefinitionBuilder.getRawBeanDefinition());
    }

    public static void createAnnotationInterceptorRegistrationBean(AnnotationInterceptorRegistration annotationInterceptorRegistration) {
        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
        // 获取bean工厂并转换为DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();

        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(annotationInterceptorRegistration.getClass());

        //构造Bean的属性的值。
        Class clazz = annotationInterceptorRegistration.getClass();
        Field[] fields = clazz.getFields();
        for (Field field :
                fields) {
            try {
                String name = field.getName();
                String type = field.getType().getTypeName();
                Method method;
                if (type.equals("boolean")) {// 基本变量
                    method = annotationInterceptorRegistration.getClass().getMethod(AbstractAnnotationProcessor.getBooleanPrefix(name));
                } else {
                    method = annotationInterceptorRegistration.getClass().getMethod("get" + AbstractAnnotationProcessor.getMethodName(name));
                }
                Object value = method.invoke(annotationInterceptorRegistration);
                beanDefinitionBuilder.addPropertyValue(name, value);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

        defaultListableBeanFactory.registerBeanDefinition(annotationInterceptorRegistration.getClass().getTypeName(), beanDefinitionBuilder.getRawBeanDefinition());
    }

    /**
     * 获取bean
     *
     * @param name bean的id
     * @param <T>
     * @return
     */
    public static <T> T getBean(String name) {
        return (T) applicationContext.getBean(name);
    }

    //通过类型获取上下文中的bean
    public static Object getBean(Class<?> requiredType) {
        return applicationContext.getBean(requiredType);
    }

}
